const vscode = require('vscode');
const fs = require('fs').promises;
const path = require('path');
const { spawn } = require('child_process');
const util = require('util');
const { isBinaryFile } = require('isbinaryfile');

/**
 * 匹配@提及的正则表达式

 * - 问题列表: @problems
 * - 终端输出: @terminal
 * - 网址: @http://example.com
 * - Git提交: @commitHash
 * - Git工作区更改: @git-changes
 */
const mentionRegex = /@((?:\/|\w+:\/\/)[^\s]+?|[a-f0-9]{7,40}\b|problems\b|terminal\b|git-changes\b)(?=[.,;:!?]?(?=[\s\r\n]|$))/;
const mentionRegexGlobal = new RegExp(mentionRegex.source, 'g');

/**
 * 打开提及的文件或文件夹
 * @param {string} mention - 提及的文件/文件夹路径
 */
function openMention(mention) {
    if (!mention) return;

    const workspaceFolders = vscode.workspace.workspaceFolders;
    const cwd = workspaceFolders?.map(folder => folder.uri.fsPath).at(0);
    if (!cwd) return;

    if (mention.startsWith('/')) {
        const relPath = mention.slice(1);
        const absPath = path.resolve(cwd, relPath);
        
        if (mention.endsWith('/')) {
            // 打开文件夹
            vscode.commands.executeCommand('revealInExplorer', vscode.Uri.file(absPath));
        } else {
            // 打开文件
            vscode.workspace.openTextDocument(vscode.Uri.file(absPath))
                .then(doc => vscode.window.showTextDocument(doc));
        }
    } else if (mention === 'problems') {
        vscode.commands.executeCommand('workbench.actions.view.problems');
    } else if (mention === 'terminal') {
        vscode.commands.executeCommand('workbench.action.terminal.focus');
    } else if (mention.startsWith('http')) {
        vscode.env.openExternal(vscode.Uri.parse(mention));
    }
}

/**
 * 解析文本中的@提及并获取相应的内容
 * @param {string} text - 包含@提及的文本
 * @returns {Promise<string>} 解析后的文本，包含提及的内容
 */
async function parseMentions(text) {
    if (!text || !text.includes('@')) return text;

    const mentions = new Set();
    let parsedText = text.replace(mentionRegexGlobal, (match, mention) => {
        mentions.add(mention);
        
        if (mention.startsWith('http')) {
            return `'${mention}' (见下方网站内容)`;
        } else if (mention.startsWith('/')) {
            const mentionPath = mention.slice(1);
            return mentionPath.endsWith('/')
                ? `'${mentionPath}' (见下方文件夹内容)`
                : `'${mentionPath}' (见下方文件内容)`;
        } else if (mention === 'problems') {
            return `工作区问题 (见下方诊断信息)`;
        } else if (mention === 'terminal') {
            return `终端输出 (见下方输出)`;
        } else if (mention === 'git-changes') {
            return `工作区变更 (见下方详情)`;
        } else if (/^[a-f0-9]{7,40}$/.test(mention)) {
            return `Git提交 '${mention}' (见下方提交信息)`;
        }
        
        return match;
    });

    const workspaceFolders = vscode.workspace.workspaceFolders;
    const cwd = workspaceFolders?.map(folder => folder.uri.fsPath).at(0);
    if (!cwd) return parsedText;

    // 处理每个唯一的提及
    const uniqueMentions = [...new Set(mentions)];
    for (const mention of uniqueMentions) {
        try {
            if (mention.startsWith('http')) {
                parsedText += `\n\n<url_content url="${mention}">\n无法直接获取网页内容。请考虑手动访问此链接。\n</url_content>`;
            } else if (mention.startsWith('/')) {
                const mentionPath = mention.slice(1);
                try {
                    const content = await getFileOrFolderContent(mentionPath, cwd);
                    if (mention.endsWith('/')) {
                        parsedText += `\n\n<folder_content path="${mentionPath}">\n${content}\n</folder_content>`;
                    } else {
                        parsedText += `\n\n<file_content path="${mentionPath}">\n${content}\n</file_content>`;
                    }
                } catch (error) {
                    if (mention.endsWith('/')) {
                        parsedText += `\n\n<folder_content path="${mentionPath}">\n获取内容错误: ${error.message}\n</folder_content>`;
                    } else {
                        parsedText += `\n\n<file_content path="${mentionPath}">\n获取内容错误: ${error.message}\n</file_content>`;
                    }
                }
            } else if (mention === 'problems') {
                try {
                    const problems = await getWorkspaceProblems(cwd);
                    parsedText += `\n\n<workspace_diagnostics>\n${problems}\n</workspace_diagnostics>`;
                } catch (error) {
                    parsedText += `\n\n<workspace_diagnostics>\n获取诊断信息错误: ${error.message}\n</workspace_diagnostics>`;
                }
            } else if (mention === 'terminal') {
                try {
                    const terminalOutput = await getTerminalOutput();
                    parsedText += `\n\n<terminal_output>\n${terminalOutput}\n</terminal_output>`;
                } catch (error) {
                    parsedText += `\n\n<terminal_output>\n获取终端输出错误: ${error.message}\n</terminal_output>`;
                }
            } else if (mention === 'git-changes') {
                try {
                    const workingState = await getGitWorkingState(cwd);
                    parsedText += `\n\n<git_working_state>\n${workingState}\n</git_working_state>`;
                } catch (error) {
                    parsedText += `\n\n<git_working_state>\n获取工作区状态错误: ${error.message}\n</git_working_state>`;
                }
            } else if (/^[a-f0-9]{7,40}$/.test(mention)) {
                try {
                    const commitInfo = await getGitCommitInfo(mention, cwd);
                    parsedText += `\n\n<git_commit hash="${mention}">\n${commitInfo}\n</git_commit>`;
                } catch (error) {
                    parsedText += `\n\n<git_commit hash="${mention}">\n获取提交信息错误: ${error.message}\n</git_commit>`;
                }
            }
        } catch (error) {
            console.error(`处理提及 ${mention} 时出错:`, error);
        }
    }

    return parsedText;
}

/**
 * 获取文件或文件夹内容
 * @param {string} mentionPath - 文件或文件夹路径
 * @param {string} cwd - 当前工作目录
 * @returns {Promise<string>} 文件或文件夹内容
 */
async function getFileOrFolderContent(mentionPath, cwd) {
    const absPath = path.resolve(cwd, mentionPath);

    try {
        const stats = await fs.stat(absPath);

        if (stats.isFile()) {
            // 检查是否为二进制文件
            const isBinary = await isBinaryFile(absPath);
            if (isBinary) {
                return "(二进制文件，无法显示内容)";
            }
            
            // 读取文件内容
            const content = await fs.readFile(absPath, 'utf8');
            return content;
        } else if (stats.isDirectory()) {
            // 列出目录内容
            const entries = await fs.readdir(absPath, { withFileTypes: true });
            let folderContent = "";
            
            // 处理目录中的每个条目
            entries.forEach((entry, index) => {
                const isLast = index === entries.length - 1;
                const linePrefix = isLast ? "└── " : "├── ";
                
                if (entry.isFile()) {
                    folderContent += `${linePrefix}${entry.name}\n`;
                } else if (entry.isDirectory()) {
                    folderContent += `${linePrefix}${entry.name}/\n`;
                } else {
                    folderContent += `${linePrefix}${entry.name}\n`;
                }
            });
            
            return folderContent.trim();
        } else {
            return `(无法读取 ${mentionPath} 的内容)`;
        }
    } catch (error) {
        throw new Error(`无法访问路径 "${mentionPath}": ${error.message}`);
    }
}

/**
 * 获取工作区问题
 * @param {string} cwd - 当前工作目录
 * @returns {Promise<string>} 工作区问题列表
 */
async function getWorkspaceProblems(cwd) {
    return new Promise((resolve) => {
        const diagnostics = vscode.languages.getDiagnostics();
        if (!diagnostics || diagnostics.length === 0) {
            resolve("未检测到错误或警告。");
            return;
        }

        let result = "";
        
        // 遍历所有诊断信息
        diagnostics.forEach(([uri, fileDiagnostics]) => {
            if (fileDiagnostics.length === 0) return;
            
            const filePath = vscode.workspace.asRelativePath(uri);
            result += `文件: ${filePath}\n`;
            
            // 按严重程度分组
            const errorDiagnostics = fileDiagnostics.filter(d => d.severity === vscode.DiagnosticSeverity.Error);
            const warningDiagnostics = fileDiagnostics.filter(d => d.severity === vscode.DiagnosticSeverity.Warning);
            
            // 添加错误
            if (errorDiagnostics.length > 0) {
                result += "  错误:\n";
                errorDiagnostics.forEach(d => {
                    const line = d.range.start.line + 1;
                    const column = d.range.start.character + 1;
                    result += `    - 行 ${line}, 列 ${column}: ${d.message}\n`;
                });
            }
            
            // 添加警告
            if (warningDiagnostics.length > 0) {
                result += "  警告:\n";
                warningDiagnostics.forEach(d => {
                    const line = d.range.start.line + 1;
                    const column = d.range.start.character + 1;
                    result += `    - 行 ${line}, 列 ${column}: ${d.message}\n`;
                });
            }
            
            result += "\n";
        });
        
        resolve(result.trim() || "未检测到错误或警告。");
    });
}

/**
 * 获取终端输出
 * @returns {Promise<string>} 终端输出内容
 */
async function getTerminalOutput() {
    return new Promise((resolve) => {
        const terminals = vscode.window.terminals;
        if (!terminals || terminals.length === 0) {
            resolve("无终端输出。");
            return;
        }

        // 尝试获取活动终端的输出
        // 注意: VS Code API目前不提供直接访问终端输出的方法
        // 这是一个模拟，实际上无法获取真实输出
        const activeTerminal = vscode.window.activeTerminal;
        if (activeTerminal) {
            resolve(`活动终端: ${activeTerminal.name}\n(注: 由于VS Code API限制，无法获取实际终端输出)`);
        } else {
            const terminalNames = terminals.map(t => t.name).join(', ');
            resolve(`可用终端: ${terminalNames}\n(注: 由于VS Code API限制，无法获取实际终端输出)`);
        }
    });
}

/**
 * 获取Git工作区状态
 * @param {string} cwd - 当前工作目录
 * @returns {Promise<string>} Git工作区状态
 */
async function getGitWorkingState(cwd) {
    try {
        return await executeCommand('git status', cwd);
    } catch (error) {
        if (error.message.includes('not a git repository')) {
            return '当前工作目录不是Git仓库。';
        }
        throw error;
    }
}

/**
 * 获取Git提交信息
 * @param {string} hash - 提交哈希
 * @param {string} cwd - 当前工作目录
 * @returns {Promise<string>} 提交信息
 */
async function getGitCommitInfo(hash, cwd) {
    try {
        return await executeCommand(`git show ${hash}`, cwd);
    } catch (error) {
        if (error.message.includes('bad revision')) {
            return `找不到提交 '${hash}'。`;
        }
        throw error;
    }
}

/**
 * 执行命令
 * @param {string} command - 要执行的命令
 * @param {string} cwd - 当前工作目录
 * @returns {Promise<string>} 命令输出
 */
function executeCommand(command, cwd) {
    return new Promise((resolve, reject) => {
        const [cmd, ...args] = command.split(' ');
        const process = spawn(cmd, args, { cwd });
        
        let stdout = '';
        let stderr = '';
        
        process.stdout.on('data', (data) => {
            stdout += data.toString();
        });
        
        process.stderr.on('data', (data) => {
            stderr += data.toString();
        });
        
        process.on('close', (code) => {
            if (code === 0) {
                resolve(stdout);
            } else {
                reject(new Error(stderr || `命令执行失败，退出码: ${code}`));
            }
        });
        
        process.on('error', (err) => {
            reject(err);
        });
    });
}

/**
 * 获取工作区可用文件列表
 * @returns {Promise<{files: string[], folders: string[]}>} 文件和文件夹列表
 */
async function getWorkspaceFiles() {
    return new Promise((resolve) => {
        const workspaceFolders = vscode.workspace.workspaceFolders;
        if (!workspaceFolders) {
            resolve({ files: [], folders: [] });
            return;
        }

        const files = [];
        const folders = [];
        
        // 使用工作区API获取文件
        vscode.workspace.findFiles('**/*', '**/node_modules/**').then(uris => {
            for (const uri of uris) {
                const relativePath = vscode.workspace.asRelativePath(uri);
                // 检查是否是文件夹 (通过检查路径是否以"/"结尾，这只是一个启发式方法)
                if (relativePath.endsWith('/')) {
                    folders.push(relativePath);
                } else {
                    files.push(relativePath);
                }
            }
            
            resolve({ files, folders });
        });
    });
}

/**
 * 搜索文件和文件夹
 * @param {string} query - 搜索查询
 * @returns {Promise<Array<{path: string, type: 'file'|'folder', label: string}>>} 搜索结果
 */
async function searchWorkspaceFiles(query) {
    if (!query) return [];
    
    const { files, folders } = await getWorkspaceFiles();
    const results = [];
    
    // 简单的模糊匹配函数
    const fuzzyMatch = (str, pattern) => {
        pattern = pattern.toLowerCase();
        str = str.toLowerCase();
        
        let patternIdx = 0;
        let strIdx = 0;
        
        while (patternIdx < pattern.length && strIdx < str.length) {
            if (pattern[patternIdx] === str[strIdx]) {
                patternIdx++;
            }
            strIdx++;
        }
        
        return patternIdx === pattern.length;
    };
    
    // 搜索文件
    for (const file of files) {
        if (fuzzyMatch(file, query)) {
            results.push({
                path: file,
                type: 'file',
                label: path.basename(file)
            });
        }
    }
    
    // 搜索文件夹
    for (const folder of folders) {
        if (fuzzyMatch(folder, query)) {
            results.push({
                path: folder,
                type: 'folder',
                label: path.basename(folder)
            });
        }
    }
    
    return results.slice(0, 10); // 限制返回10个结果
}

module.exports = {
    mentionRegex,
    mentionRegexGlobal,
    openMention,
    parseMentions,
    getFileOrFolderContent,
    getWorkspaceProblems,
    getTerminalOutput,
    getGitWorkingState,
    getGitCommitInfo,
    searchWorkspaceFiles
}; 